
#ifndef __SMP_TST_H__
#define __SMP_TST_H__


#pragma warning( push )
#pragma warning(disable : 4996)
#pragma warning(disable : 4297)


#include <tchar.h>

#include "MiscUtil.h"


//
// C file can include this part
//
#ifdef __cplusplus
extern "C" {
#endif

//
// use these defines to add test functions
#define SMPTST_FUNCTION(func_name, des) EXTERNC __declspec(dllexport allocate(".utest$__t")) struct SmpTstNode _testnode##func_name={SMPTST_NODE_SIG, _T(#func_name), des, func_name, NULL, NULL}
#define SMPTST_SUB_FUNCTION(func_name, des, parent) EXTERNC __declspec(dllexport allocate(".utest$__t")) struct SmpTstNode _testnode##func_name={SMPTST_NODE_SIG, _T(#func_name), des, func_name, &_testnode##parent, NULL}
#define SMPTST_GROUP(group_name, des) EXTERNC __declspec(dllexport allocate(".utest$__t")) struct SmpTstNode _testnode##group_name={SMPTST_NODE_SIG, _T(#group_name), des, NULL, NULL, NULL}
#define SMPTST_SUB_GROUP(group_name, des, parent) EXTERNC __declspec(dllexport allocate(".utest$__t")) struct SmpTstNode _testnode##group_name={SMPTST_NODE_SIG, _T(#group_name), des, NULL, &_testnode##parent, NULL}

#define SMPTST_INITIALIZE(func_name, des) EXTERNC __declspec(dllexport allocate(".utest$__i")) struct SmpTstNode _testnode##func_name={SMPTST_NODE_SIG, _T(#func_name), des, func_name, NULL, NULL}
#define SMPTST_CLEANUP(func_name, des) EXTERNC __declspec(dllexport allocate(".utest$__c")) struct SmpTstNode _testnode##func_name={SMPTST_NODE_SIG, _T(#func_name), des, func_name, NULL, NULL}

// for SMPTST_XXX symbols is not referenced directly, 
//  if __declspec(dllexport) is not specified
// then in release build these symbols maybe "stripped",
// add:
// #pragma comment(linker, "/include:"SMPTST_LINK_INCLUDE(func_name))
// to force include this symbol in final program
#define SMPTST_LINK_INCLUDE(func_name) "__testnode"#func_name


enum SMPTST_RSLT{SMPTST_RSLT_UNKNWN, SMPTST_RSLT_OK, SMPTST_RSLT_FAILD};

struct SmpTstFunCntx
{
// for result context
	enum SMPTST_RSLT rslt;
	TCHAR* pstr;

// for io context
//	ISmpIO* pIO;
	VOID* pIO;
};
#ifdef __cplusplus
#define EXTRACT_CNTX_IO(pCntx)	(ISmpIO*)(pCntx)
#else
// for c code call SmpIOPrintf etc directly
#endif

// test function wrapper!
typedef VOID (*fnTestFun)(struct SmpTstFunCntx* pv);

//
// call these two define to return test result
#define SMPTST_RSLT_RETURN(pv, f, exp)	\
{	\
	struct SmpTstFunCntx* pRslt=(struct SmpTstFunCntx*)(pv);	\
	pRslt->rslt=(f)?SMPTST_RSLT_OK:SMPTST_RSLT_FAILD;	\
	pRslt->pstr=ExpToMallocBuf exp ;		\
	return;	\
}

#define SMPTST_ASSERT_RETURN(pv, f, exp)	\
{	\
	if(!f)	\
	{	\
		struct SmpTstFunCntx* pRslt=(struct SmpTstFunCntx*)(pv);	\
		pRslt->rslt=(f)?SMPTST_RSLT_OK:SMPTST_RSLT_FAILD;	\
		pRslt->pstr=ExpToMallocBuf exp;		\
		return;	\
	}	\
}


#pragma section(".utest$__a",read,write)	// start
#pragma section(".utest$__c",read,write)	//clean functions
#pragma section(".utest$__d",read,write)	// stub
#pragma section(".utest$__i",read,write)	// init functions
#pragma section(".utest$__j",read,write)	// stub
#pragma section(".utest$__t",read,write)	// test functions
#pragma section(".utest$__z",read,write)	// end


struct SmpTstNode
{
#define SMPTST_NODE_SIG   0x444e5354  //"TSND"
    int sig;
    const TCHAR* pszTestFunc;
    const TCHAR* pszDes;
    fnTestFun pfn;
    struct SmpTstNode* pParent;

    VOID* pv;
};

struct SmpTstNode* InitSmpTstNode(struct SmpTstNode* pNode, const TCHAR* pszTestFunc, const TCHAR* pszTestDes, fnTestFun pfn, struct SmpTstNode* pParent, VOID* pv);


#ifdef __cplusplus
}
#endif


//
// only cpp file can include this part
//
#ifdef __cplusplus

#include <string>
#include <vector>
#include <utility>
#include <algorithm>
#include <functional>

#include "SmpIO.h"

#include "tree.h"
#include "unique_tree.h"

using namespace std;
using namespace tcl;

class CSmpTstRsltAssert
{
public:
    CSmpTstRsltAssert(BOOL fResult, const TCHAR* str)
        :m_fResult(fResult), m_str(str)
    {};

public:
    _tstring m_str;
    BOOL    m_fResult;
};


enum SMPTST_CASE {SMPTST_CASE_NODE=0, SMPTST_CASE_TREE, SMPTST_CASE_DEEP_TREE};

class CSmpTstRslt
{
private:
    struct SmpTstRslt
    {
    template<class T>
        SmpTstRslt(SMPTST_RSLT enRslt, T strRslt, DWORD dwS, DWORD dwMS, DWORD dwNS)
            :m_enRslt(enRslt), m_strRslt(strRslt), m_dwS(dwS),  m_dwMS(dwMS),  m_dwNS(dwNS)
        {};
    //  SmpTstRslt(SMPTST_RSLT enRslt, const TCHAR* pszRslt, DWORD dwS, DWORD dwMS, DWORD dwNS)
    //      :m_enRslt(enRslt), m_strRslt(pszRslt), m_dwS(dwS),  m_dwMS(dwMS),  m_dwNS(dwNS)
    //  {};
        SMPTST_RSLT m_enRslt;
        _tstring m_strRslt;
        DWORD m_dwS;
        DWORD m_dwMS;
        DWORD m_dwNS;

    };

public:
    CSmpTstRslt()
        :m_dwPassed(0), m_dwFaild(0), m_dwUnknown(0)
    {};

public:
template <class T>
    VOID AddRslt(SMPTST_RSLT enRslt, T strRslt, DWORD dwS, DWORD dwMS, DWORD dwNS);
//  VOID AddRslt(SMPTST_RSLT enRslt, _tstring& strRslt, DWORD dwS, DWORD dwMS, DWORD dwNs);
    VOID GetRsltInfo(DWORD* pdwTstTimes, DWORD* pdwPass, DWORD* pdwFail, DWORD* pdwUnknown);
    VOID GetLastRslt(SMPTST_RSLT* penRslt, const TCHAR** pszRslt, DWORD* pdwS, DWORD* pdwMS, DWORD* pdwNS);

public:
    VOID Print(ISmpIO* pIO, BOOL fAllRslt=FALSE);

private:
    static VOID DoPrint(SmpTstRslt* pRslt, ISmpIO* pIO);

private:
    vector<SmpTstRslt> m_vRslt;
    DWORD m_dwPassed;
    DWORD m_dwFaild;
    DWORD m_dwUnknown;

};

template <class T>
VOID CSmpTstRslt::AddRslt(SMPTST_RSLT enRslt, T szRslt, DWORD dwS, DWORD dwMS, DWORD dwNS)
{
    m_vRslt.push_back(SmpTstRslt(enRslt, szRslt, dwS, dwMS, dwNS));
    if(SMPTST_RSLT_OK==enRslt)
    {
        m_dwPassed++;
    }
    else if(SMPTST_RSLT_FAILD==enRslt)
    {
        m_dwFaild++;
    }
    else
    {
        m_dwUnknown++;
    }
}

class CSmpTstNode
{
public:
	CSmpTstNode()
	{
		InitializeCriticalSection(&m_cs);
	}

	CSmpTstNode(const CSmpTstNode& node)
		:m_pNode(node.m_pNode)
	{
		InitializeCriticalSection(&m_cs);
		m_pNode->pv=(VOID*)this;
	};

    CSmpTstNode(SmpTstNode* pNode)
                :m_pNode(pNode)
    {
		InitializeCriticalSection(&m_cs);
        m_pNode->pv=(VOID*)this;
    };

	~CSmpTstNode()
	{
		DeleteCriticalSection(&m_cs);
	};
public:
    static BOOL IsValidNode(SmpTstNode* pc);

public:
    fnTestFun GetTstFun(){return m_pNode->pfn;}
	const TCHAR* GetTstName(){return m_pNode->pszTestFunc;}
	const TCHAR* GetTstDescription(){return m_pNode->pszDes;}

public:
    VOID Print(ISmpIO* pIO, BOOL fWithRslt, BOOL fAllRslt=FALSE);

public:
template <class T>
	VOID AddRslt(SMPTST_RSLT enRslt, T strRslt, DWORD dwS, DWORD dwMS, DWORD dwNS)
		{
			EnterCriticalSection(&m_cs);
			m_Rslt.AddRslt(enRslt, strRslt, dwS, dwMS, dwNS);
			LeaveCriticalSection(&m_cs);
		};
    VOID GetRsltInfo(DWORD* pdwTstTimes, DWORD* pdwPass, DWORD* pdwFail, DWORD* pdwUnknown)
        {m_Rslt.GetRsltInfo(pdwTstTimes, pdwPass, pdwFail, pdwUnknown);};
    VOID GetLastRslt(SMPTST_RSLT* penRslt, const TCHAR** pszRslt, DWORD* pdwS, DWORD* pdwMS, DWORD* pdwNS)
        {m_Rslt.GetLastRslt(penRslt, pszRslt, pdwS, pdwMS, pdwNS);};

// used by find_if
public:
	bool operator == (const CSmpTstNode& node) const
	{return m_pNode==node.m_pNode;};
	bool operator < (const CSmpTstNode& node) const
	{return m_pNode<node.m_pNode;};
    BOOL NameEqual(const TCHAR* pstr);

private:
    SmpTstNode* m_pNode;
    CSmpTstRslt m_Rslt;

	CRITICAL_SECTION m_cs;
};

class ISmpTstCaseS
{
public:
	virtual ~ISmpTstCaseS(){};

public:
    virtual CSmpTstNode* GetIrstCase()=0;
    virtual CSmpTstNode* GetNextCase()=0;
};

class CSmpTstCasesNode
    :public ISmpTstCaseS
{
public:
	virtual ~CSmpTstCasesNode(){};

public:
    CSmpTstCasesNode(CSmpTstNode* pNode):m_pNode(pNode){};
public:
    CSmpTstNode* GetIrstCase(){return m_pNode;};
    CSmpTstNode* GetNextCase(){return NULL;};
private:
    CSmpTstNode* m_pNode;
};

template <class T>
class TSmpTstCasesTree
    :public ISmpTstCaseS
{
public:
    TSmpTstCasesTree(CSmpTstNode* pRoot, T& itBgn, T& itEnd)
            :m_pRoot(pRoot), m_itBgn(itBgn), m_itEnd(itEnd)
    {};
	virtual ~TSmpTstCasesTree(){};

public:
    CSmpTstNode* GetIrstCase()
    {
        if (m_itBgn!=m_itEnd)
		{
			m_it=m_itBgn;
		}
        return m_pRoot;
    };
    CSmpTstNode* GetNextCase()
    {
		if (m_itBgn!=m_itEnd)
		{
			if (m_it!=m_itEnd)
			{
				T it=m_it;
				m_it++;
				return &(*it);
			}
		}


        return NULL;
    };

private:
    CSmpTstNode* m_pRoot;   //add root to out
    T m_itBgn;
    T m_itEnd;

    T m_it;
};

template <class T>
class TSmpTstCaseIter
    :public ISmpTstCaseS
{
public:
    TSmpTstCaseIter(T& itBgn, T& itEnd)
            :m_itBgn(itBgn), m_itEnd(itEnd), m_it(itBgn)
    {};
	virtual ~TSmpTstCaseIter(){};

public:
    CSmpTstNode* GetIrstCase()
    {
        if (m_itBgn!=m_itEnd)
		{
			m_it=m_itBgn;
			m_it++;
			return &(*m_itBgn);
		}
        return NULL;
    };
    CSmpTstNode* GetNextCase()
    {
		if (m_it!=m_itEnd)
		{
			T it=m_it;
			m_it++;
			return &(*it);
		}

        return NULL;
    };

private:
    T m_itBgn;
    T m_itEnd;

    T m_it;
};

class CSmpTstCasesArray
    :public ISmpTstCaseS
{
public:
	virtual ~CSmpTstCasesArray(){};

public:
    CSmpTstCasesArray(CSmpTstNode* pBgn, CSmpTstNode* pEnd)
		:m_pBgn(pBgn),m_pEnd(pEnd),m_pCur(pBgn)
	{};
public:
    CSmpTstNode* GetIrstCase()
	{m_pCur=m_pBgn+1; return m_pBgn;};
    CSmpTstNode* GetNextCase()
	{return (m_pCur==m_pEnd)?NULL:m_pCur++;};

private:
    CSmpTstNode* m_pBgn;
	CSmpTstNode* m_pEnd;
	CSmpTstNode* m_pCur;
};

class CSmpTstCaseS
    :public ISmpTstCaseS
{
public:
	virtual ~CSmpTstCaseS();

public:
    CSmpTstCaseS(){};

public:
    CSmpTstNode* GetIrstCase()
	{
		m_it=m_vCase.begin();
		return (*m_it)->GetIrstCase();
	};
    CSmpTstNode* GetNextCase();

public:
	void InsertCase(ISmpTstCaseS* pcase){m_vCase.push_back(pcase);};
	bool empty(){return m_vCase.empty();};

// tmp var	
private:
	vector<ISmpTstCaseS*>::iterator m_it;

private:
	vector<ISmpTstCaseS*> m_vCase;
};


class CSmpTstTree
{
public:
    CSmpTstTree()
		: m_tree(CSmpTstNode(InitSmpTstNode(&m_noderoot, TEXT("SMP_TST_ROOT"), NULL, NULL, NULL, NULL)))
    {
        m_noderoot.pv=m_tree.get();
    };


public:
    BOOL BuildTree(SmpTstNode* pIrst, SmpTstNode* pLst);

public:
    ISmpTstCaseS* GetTstCase(const TCHAR* pszNode, SMPTST_CASE type);
    VOID ReleaseTstCases(ISmpTstCaseS* p){delete p;};

public:
    VOID Print(const TCHAR* pszRoot, BOOL fWithRslt, ISmpIO* pIO);

private:
    BOOL AddTestNode(SmpTstNode* pNode);
    VOID Print(unique_tree<CSmpTstNode>* ptree, BOOL fWithRslt, ISmpIO* pIO);
	unique_tree<CSmpTstNode>* FindTree(const TCHAR* pszRoot);

private:
    //root stub
    SmpTstNode m_noderoot;

    unique_tree<CSmpTstNode> m_tree;

// used temply when get result info
private:
    DWORD m_dwTtl, m_dwOk, m_dwFaild, m_dwUnknown;
};


class CSmpTstArray
{
public:
	CSmpTstArray()
	{};

public:
	VOID BuildArray(SmpTstNode* pBgn, SmpTstNode* pEnd);
    ISmpTstCaseS* GetTstCase()
	{return new TSmpTstCaseIter<vector<CSmpTstNode>::iterator>(m_vNodeS.begin(), m_vNodeS.end());};
    VOID ReleaseTstCases(ISmpTstCaseS* p){delete p;};

private:
	vector<CSmpTstNode> m_vNodeS;
};


class CSmpTester
{
private:
struct TstThrdPara
{
    CSmpTester* pthis;
    CSmpTstNode* pcTstNode;
	ISmpIO* pIO;
};

public:
    CSmpTester()
    {
		InitializeCriticalSection(&m_cs);
		QueryPerformanceFrequency(&m_liFreq);
	};
    ~CSmpTester()
    {
		DeleteCriticalSection(&m_cs);
    };

public:
	BOOL BuildUpTstInitArray(SmpTstNode* pnodeBgn, SmpTstNode* pnodeEnd)
	{m_InitArray.BuildArray(pnodeBgn, pnodeEnd); return TRUE;};
	BOOL BuildUpTstCleanArray(SmpTstNode* pnodeBgn, SmpTstNode* pnodeEnd)
	{m_CleanArray.BuildArray(pnodeBgn, pnodeEnd); return TRUE;};
	BOOL BuildUpTstTree(SmpTstNode* pnodeBgn, SmpTstNode* pnodeEnd)
	{return m_TstTree.BuildTree(pnodeBgn, pnodeEnd);};
	
public:
	// dwPrio: INVALID_DWORD don't change priority
    BOOL DoTest(const TCHAR* psz, SMPTST_CASE type, BOOL fSync, DWORD dwTO, DWORD dwPrio, ISmpIO* pIO, HANDLE hCancleComplete);
	VOID DoInitCleanFunc(BOOL fInit, DWORD dwTO, ISmpIO* pIO);

public:
	VOID Print(const TCHAR* pszCases, BOOL fWithRslt, ISmpIO* pIO);

private:
	ISmpTstCaseS* GetTstCaseS(const TCHAR* pszCases, SMPTST_CASE type);

	// dwPrio:INVALID_DWORD not care the thread priority
    HANDLE ExeTest(CSmpTstNode* pcTstNode, DWORD dwPrio, ISmpIO* pIO);
    static DWORD WINAPI TstThreadWrap(LPVOID lpParameter);
    VOID TstThread(CSmpTstNode* pcTstNode, ISmpIO* pIO);
 
private:
    CSmpTstTree m_TstTree;
    CSmpTstArray m_InitArray;
    CSmpTstArray m_CleanArray;
	
private:
    LARGE_INTEGER m_liFreq;

private:
	CRITICAL_SECTION m_cs;
	

};

//
//---- help functions to construct test system ----
BOOL BuildUpDefTester(CSmpTester* ptester);


//
//==== implements ====
//
#if (defined(SMPTST_IMP)|defined(KEN_LIB_IMP))

SmpTstNode* InitSmpTstNode(SmpTstNode* pNode, const TCHAR* pszTestFunc, const TCHAR* pszTestDes, fnTestFun pfn, struct SmpTstNode* pParent, VOID* pv)
{
	pNode->sig=SMPTST_NODE_SIG;
	pNode->pszTestFunc=pszTestFunc;
	pNode->pszDes=pszTestDes;
	pNode->pfn=pfn;
	pNode->pParent=pParent;
	pNode->pv=pv;
	return pNode;
}


//
//---- implement of CSmpTstRslt ----
//
VOID CSmpTstRslt::GetRsltInfo(DWORD* pdwTstTimes, DWORD* pdwPass, DWORD* pdwFail, DWORD* pdwUnknown)
{
    if(pdwTstTimes){*pdwTstTimes=(DWORD)m_vRslt.size();}
    if(pdwPass){*pdwPass=m_dwPassed;}
    if(pdwFail){*pdwFail=m_dwFaild;}
    if(pdwUnknown){*pdwUnknown=m_dwUnknown;}
}

VOID CSmpTstRslt::GetLastRslt(SMPTST_RSLT* penRslt, const TCHAR** pszRslt, DWORD* pdwS, DWORD* pdwMS, DWORD* pdwNS)
{
	if(0!=m_vRslt.size())
	{
		if(penRslt){*penRslt=m_vRslt.back().m_enRslt;}
		if(pszRslt){*pszRslt=m_vRslt.back().m_strRslt.c_str();}
		if(pdwS){*pdwS=m_vRslt.back().m_dwS;}
		if(pdwMS){*pdwMS=m_vRslt.back().m_dwMS;}
		if(pdwNS){*pdwNS=m_vRslt.back().m_dwNS;}
	}
	else
	{
		if(penRslt){*penRslt=SMPTST_RSLT_UNKNWN;}
		if(pszRslt){*pszRslt=NULL;}
		if(pdwS){*pdwS=0;}
		if(pdwMS){*pdwMS=0;}
		if(pdwNS){*pdwNS=0;}
	}
}

VOID CSmpTstRslt::Print(ISmpIO* pIO, BOOL fAllRslt)
{
    if(fAllRslt)
    {
//        for_each(m_vRslt.begin(), m_vRslt.end(), bind2nd(ptr_fun(CSmpTstRslt::DoPrint), pIO));
        for(vector<SmpTstRslt>::iterator it=m_vRslt.begin(); it!=m_vRslt.end(); it++)
        {
            DoPrint(&(*it), pIO);
        }
    }
    else
    {
        if(0!=m_vRslt.size())
        {
            DoPrint(&m_vRslt.back(), pIO);
        }
    }
}

VOID CSmpTstRslt::DoPrint(SmpTstRslt* pRslt, ISmpIO* pIO)
{
    if(SMPTST_RSLT_UNKNWN==pRslt->m_enRslt)
    {
        pIO->Printf(TEXT("test result unknown! %s\r\n"), pRslt->m_strRslt.c_str());
    }
    else if(SMPTST_RSLT_OK==pRslt->m_enRslt)
    {
        pIO->Printf(TEXT("test result ok! %s\r\n"), pRslt->m_strRslt.c_str());
    }
    else
    {
        pIO->Printf(TEXT("test result faild! %s\r\n"), pRslt->m_strRslt.c_str());
    }
    
    pIO->Printf(TEXT("use %d.%d,%d Seconds\r\n"), pRslt->m_dwS, pRslt->m_dwMS, pRslt->m_dwNS);
}

//
//---- implement of CSmpTstNode ----
//
BOOL CSmpTstNode::IsValidNode(SmpTstNode* pc)
{
    if( (SMPTST_NODE_SIG==pc->sig)
        &&(NULL!=pc->pszTestFunc) )
    {
        return TRUE;
    }

    return FALSE;
}

VOID CSmpTstNode::Print(ISmpIO* pIO, BOOL fWithRslt, BOOL fAllRslt)
{
    if(m_pNode->pszDes)
	{
		pIO->Printf(TEXT("TestFunction:%s  --%s\r\n"), m_pNode->pszTestFunc, m_pNode->pszDes);
    }
	else
	{
		pIO->Printf(TEXT("TestFunction:%s\r\n"), m_pNode->pszTestFunc);
	}

    if(fWithRslt)
    {
        m_Rslt.Print(pIO, fAllRslt);

		if(fAllRslt)
		{
			DWORD dwTstTimes, dwPass, dwFail , dwUnknown;
			m_Rslt.GetRsltInfo(&dwTstTimes, &dwPass, &dwFail, &dwUnknown);
			pIO->Printf(TEXT("perferm test %d times, pass:%d, faild:%d, unknown:%d\r\n")
				, dwTstTimes, dwPass, dwFail, dwUnknown);
		}
    }
}
BOOL CSmpTstNode::NameEqual(const TCHAR* pstr)
{
    if(0==_tcscmp(m_pNode->pszTestFunc, pstr))
    {
        return TRUE;
    }

    return FALSE;
}

//
//---- implement of CSmpTstCaseS ----
//
CSmpTstCaseS::~CSmpTstCaseS()
{
	for(m_it=m_vCase.begin(); m_it!=m_vCase.end(); m_it++)
	{
		delete (*m_it);
	}
}

CSmpTstNode* CSmpTstCaseS::GetNextCase()
{
	CSmpTstNode* ret=(*m_it)->GetNextCase();
	if(NULL==ret)
	{
		m_it++;
		if(m_it==m_vCase.end())
		{
			return NULL;
		}
		else
		{
			return (*m_it)->GetIrstCase();
		}
	}
	else
	{
		return ret;
	}
}


//
//---- implement of CSmpTstTree ----
//

BOOL CSmpTstTree::BuildTree(SmpTstNode* pIrst, SmpTstNode* pLst)
{
    vector<SmpTstNode*> vectToAdd;

    //
    // add directly
    for(SmpTstNode* pt=pIrst; pt<pLst; pt++)
    {
        if(!AddTestNode(pt))
        {
            vectToAdd.push_back(pt);
        }
    }

    //
    // add after parent added
    int iAddNumb;
    do
    {
        iAddNumb=0;
        for(vector<SmpTstNode*>::iterator it=vectToAdd.begin(); it!=vectToAdd.end(); it++)
        {
            if(AddTestNode(*it))
            {
                vectToAdd.erase(it);	// erase will modity the container and iterator, so can't use the it again
                iAddNumb++;
				break;
            }
        }
    }while(iAddNumb!=0);
    
    if(0!=vectToAdd.size())
    {
        return FALSE;
    }

    return TRUE;
}

BOOL CSmpTstTree::AddTestNode(SmpTstNode* pt)
{
    unique_tree<CSmpTstNode>* ptreeParent;
    CSmpTstNode* pParent=NULL;

    // find parent
    if(pt->pParent)
    {
        pParent=(CSmpTstNode*)(pt->pParent->pv);
		// parent had not been add to tree
		if(NULL==pParent)
		{
			return FALSE;
		}
//1 !!! if use insert(pos, storagetype) the find_deep not works !!!
//        unique_tree<CSmpTstNode*>::iterator it=m_tree.find_deep(pParent);
        unique_tree<CSmpTstNode>::level_order_iterator it=find(m_tree.level_order_begin(), m_tree.level_order_end(), *pParent);

        if(it==m_tree.level_order_end())
        {
            return FALSE;
        }

        ptreeParent=it.node();
    }
    // add to root
    else
    {
        ptreeParent=&m_tree;
    }


//1 !!! it seems that the insert can't define the position !!!
    if(ptreeParent->end()==ptreeParent->insert(ptreeParent->end(), CSmpTstNode(pt)))
//	if(ptreeParent->end()==ptreeParent->insert(pcntx))
    {
        return FALSE;
    }

    return TRUE;
}

ISmpTstCaseS* CSmpTstTree::GetTstCase(const TCHAR* pszNode, SMPTST_CASE type)
{
    unique_tree<CSmpTstNode>* ptree=FindTree(pszNode);
	if(NULL==ptree)
	{
		return NULL;
	}

    ISmpTstCaseS* pcases=NULL;
    switch (type)
    {
    case SMPTST_CASE_NODE:
        pcases=new CSmpTstCasesNode(ptree->get());
        break;

    case SMPTST_CASE_TREE:
        pcases=new TSmpTstCasesTree<unique_tree<CSmpTstNode>::iterator>(ptree->get(),  ptree->begin(), ptree->end());
        break;

    case SMPTST_CASE_DEEP_TREE:
        pcases=new TSmpTstCasesTree<unique_tree<CSmpTstNode>::pre_order_iterator>(ptree->get(), ptree->pre_order_begin(),ptree->pre_order_end());
       break;

    default:
        break;
    }

    return pcases;
}

VOID CSmpTstTree::Print(const TCHAR* pszRoot, BOOL fWithRslt, ISmpIO* pIO)
{
    unique_tree<CSmpTstNode>* ptreeRoot=FindTree(pszRoot);
	if(NULL==ptreeRoot)
	{
		pIO->Printf(0, TEXT("Can't find node:%s\r\n"), pszRoot);
		return;
	}

    ptreeRoot->get()->Print(pIO, fWithRslt, TRUE);
	pIO->Puts(TEXT(""));

    pIO->IncDeep();
    ptreeRoot->get()->GetRsltInfo(&m_dwTtl, &m_dwOk, &m_dwFaild, &m_dwUnknown);
    Print(ptreeRoot, fWithRslt, pIO);
    pIO->DecDeep();

    pIO->Printf(0, TEXT("tatol test cases:%d, passed:%d, faild:%d, unknown:%d\r\n"), m_dwTtl, m_dwOk, m_dwFaild, m_dwUnknown);
    
}

VOID CSmpTstTree::Print(unique_tree<CSmpTstNode>* ptree, BOOL fWithRslt, ISmpIO* pIO)
{
    DWORD dwTtl, dwOk, dwFaild, dwUnknown;

    for(unique_tree<CSmpTstNode>::iterator it=ptree->begin(); it!=ptree->end(); it++)
    {
        it->Print(pIO, fWithRslt, TRUE);
//		pIO->Puts(TEXT(""));
        pIO->IncDeep();
        Print(it.node(), fWithRslt, pIO);
        pIO->DecDeep();

        it->GetRsltInfo(&dwTtl, &dwOk, &dwFaild, &dwUnknown);
        m_dwTtl+=dwTtl;
        m_dwOk+=dwOk;
        m_dwFaild+=dwFaild;
        m_dwUnknown+=dwUnknown;
    }
}

unique_tree<CSmpTstNode>* CSmpTstTree::FindTree(const TCHAR* pszRoot)
{
    if(NULL==pszRoot)
    {
        return &m_tree;
    }
    else
    {
		// root?
		if(m_tree.get()->NameEqual(pszRoot))
		{
			return &m_tree;
		}
		else
		{
			unique_tree<CSmpTstNode>::level_order_iterator it;
			it=find_if(m_tree.level_order_begin(), m_tree.level_order_end(), bind2nd(mem_fun_ref(&CSmpTstNode::NameEqual), pszRoot));
			if(it==m_tree.level_order_end())
			{
				return NULL;
			}
			
			return it.node();
		}
    }
}

//
//---- implement of CSmpTstArray ----
//
VOID CSmpTstArray::BuildArray(SmpTstNode* pBgn, SmpTstNode* pEnd)
{
	for(SmpTstNode* pNode=pBgn; pNode!=pEnd; pNode++)
	{
		m_vNodeS.push_back(CSmpTstNode(pNode));
	}
};

//
//---- implement of CSmpTstTree ----
//
VOID CSmpTester::DoInitCleanFunc(BOOL fInit, DWORD dwTO, ISmpIO* pIO)
{
    ISmpTstCaseS* pTstCase;
    CSmpTstNode* pNode=NULL;
    HANDLE hExeThrd;

	if(fInit)
	{
		pTstCase=m_InitArray.GetTstCase();
	}
	else
	{
		pTstCase=m_CleanArray.GetTstCase();
	}

    if(0==dwTO)
    {
        dwTO=INFINITE;
    }
    
    for(pNode=pTstCase->GetIrstCase(); pNode!=NULL; pNode=pTstCase->GetNextCase())
    {
		if(NULL==pNode->GetTstFun())
		{
			continue;
		}

		if(NULL!=pNode->GetTstName())
		{
			if(pIO)
			{
				pIO->Printf(TEXT("Do %s function:%s\r\n"), fInit?TEXT("Init"):TEXT("CleanUp"), pNode->GetTstName());
			}
		}

        hExeThrd=ExeTest(pNode, INVALID_DWORD, pIO);
        if(hExeThrd)
        {
            if(WAIT_TIMEOUT==WaitForSingleObject(hExeThrd, dwTO))
            {
                TerminateThread(hExeThrd, 0);
                pNode->AddRslt(SMPTST_RSLT_UNKNWN, TEXT("Test timeout!"), dwTO/1000, dwTO%1000, 0);
            }
			else
			{
				CloseHandle(hExeThrd);
			}
        }
		pNode->Print(pIO, TRUE, FALSE);
    }
	
	if(fInit)
	{
		m_InitArray.ReleaseTstCases(pTstCase);
	}
	else
	{
		m_CleanArray.ReleaseTstCases(pTstCase);
	}
}

BOOL CSmpTester::DoTest(const TCHAR* psz, SMPTST_CASE type, BOOL fSync, DWORD dwTO, DWORD dwPrio, ISmpIO* pIO, HANDLE hCancle)
{
    ISmpTstCaseS* pTstCase;
    CSmpTstNode* pNode=NULL;
    DWORD dwCases=0;

    HANDLE hExeThrd;
    vector<pair<HANDLE, CSmpTstNode*>> vExe;

    if(0==dwTO)
    {
        dwTO=INFINITE;
    }
    
    pTstCase=GetTstCaseS(psz, type);
    if(!pTstCase)
    {
		pIO->Puts(TEXT(""));
		pIO->Printf(0, TEXT("Can't find test case:%s\r\n"), psz);
        return FALSE;
    }

	HANDLE h[2];
	DWORD dwWaitCnt;
	DWORD dwWaitRet;
	DWORD dwTickStart, dwTickEnd;
	BOOL fRet=TRUE;
	if(hCancle)
	{
		h[1]=hCancle;
		dwWaitCnt=2;
	}
	else
	{
		h[1]=NULL;
		dwWaitCnt=1;
	}

    for(pNode=pTstCase->GetIrstCase(); pNode!=NULL; pNode=pTstCase->GetNextCase())
    {
		if(NULL==pNode->GetTstFun())
		{
			continue;
		}

		dwTickStart=GetTickCount();
        hExeThrd=ExeTest(pNode, INVALID_DWORD, pIO);
        if(hExeThrd)
        {
            if(fSync)
            {
				h[0]=hExeThrd;
				dwWaitRet=WaitForMultipleObjects(dwWaitCnt, h, FALSE, dwTO);
                if(WAIT_TIMEOUT==dwWaitRet)
                {
                    TerminateThread(hExeThrd, 0);
                    pNode->AddRslt(SMPTST_RSLT_UNKNWN, TEXT("Test timeout!"), dwTO/1000, dwTO%1000, 0);
                }
				// test thread exist
				else if(WAIT_OBJECT_0==dwWaitRet)
				{
					CloseHandle(hExeThrd);
				}
				//user cancel
				else
				{
                    TerminateThread(hExeThrd, 0);
					dwTickEnd=GetTickCount();
                    pNode->AddRslt(SMPTST_RSLT_UNKNWN, TEXT("User cancel test!"), (dwTickEnd-dwTickStart)/1000, (dwTickEnd-dwTickStart)%1000, 0);					
					fRet=FALSE;
				}
            }
            else
            {
                vExe.push_back(pair<HANDLE, CSmpTstNode*>(hExeThrd, pNode));
            }
        }
    }

    if(!fSync)
    {
        BOOL fTerminateAll=FALSE;

        for(vector<pair<HANDLE, CSmpTstNode*>>::iterator it=vExe.begin(); it!=vExe.end(); it++)
        {
			h[0]=it->first;
			dwWaitRet=WaitForMultipleObjects(dwWaitCnt, h, FALSE, dwTO);
            if(WAIT_TIMEOUT==dwWaitRet)
            {
                TerminateThread(it->first, 0);
                it->second->AddRslt(SMPTST_RSLT_UNKNWN, TEXT("Test timeout!"), dwTO/1000, dwTO%1000, 0);
                fTerminateAll=TRUE;
                // timeout so waitfor 0ms
                dwTO=0;
            }
			// test thread exist
			else if(WAIT_OBJECT_0==dwWaitRet)
			{
				CloseHandle(it->first);
			}
			//user cancel
			else
			{
				TerminateThread(it->first, 0);
				dwTickEnd=GetTickCount();
				it->second->AddRslt(SMPTST_RSLT_UNKNWN, TEXT("User cancel test!"), (dwTickEnd-dwTickStart)/1000, (dwTickEnd-dwTickStart)%1000, 0);					
				fRet=FALSE;
			}
        }
    }

    SMPTST_RSLT enRslt;
    DWORD dwOk=0, dwFaild=0, dwUndef=0, dwCaseNumb=0;

	EnterCriticalSection(&m_cs);
    pIO->Puts(TEXT("the last result for each test:\r\n"));
    pIO->IncDeep();
    for(pNode=pTstCase->GetIrstCase(); pNode!=NULL; pNode=pTstCase->GetNextCase())
    {
		if(NULL==pNode->GetTstFun())
		{
			continue;
		}

        dwCaseNumb++;
        pNode->Print(pIO, TRUE, FALSE);
//		pIO->Puts(TEXT("\r\n"));
        pNode->GetLastRslt(&enRslt, NULL, NULL, NULL, NULL);
        if(SMPTST_RSLT_UNKNWN==enRslt)
        {
            dwUndef++;
        }
        else if(SMPTST_RSLT_OK==enRslt)
        {
            dwOk++;
        }
        else
        {
            dwFaild++;
        }
    }

    pIO->DecDeep();
    pIO->Printf(TEXT("total case:%d, passed:%d, faild:%d, noresult:%d\r\n"), dwCaseNumb, dwOk, dwFaild, dwUndef);

    m_TstTree.ReleaseTstCases(pTstCase);
	LeaveCriticalSection(&m_cs);

	return fRet;

}

VOID CSmpTester::Print(const TCHAR* pszCases, BOOL fWithRslt, ISmpIO* pIO)
{
	if( (NULL==pszCases)
		|| (0==_tcscmp(TEXT(""), pszCases)) )
	{
		m_TstTree.Print((const TCHAR*)NULL, fWithRslt, pIO);
		return;
	}

	_tistringstream strCases(pszCases);
	
	TCHAR bufCase[256];
	while(strCases.getline(bufCase, ARRAYOF(bufCase), ','))
	{
		m_TstTree.Print(bufCase, fWithRslt, pIO);
	}
}

ISmpTstCaseS* CSmpTester::GetTstCaseS(const TCHAR* pszCases, SMPTST_CASE type)
{
	if( (NULL==pszCases)
		|| (0==_tcscmp(TEXT(""), pszCases)) )
	{
		return m_TstTree.GetTstCase(NULL, type);
	}

    CSmpTstCaseS* pcases=new CSmpTstCaseS;
	_tistringstream strCases(pszCases);
	
	TCHAR bufCase[256];
	while(strCases.getline(bufCase, ARRAYOF(bufCase), ','))
	{
		ISmpTstCaseS* pcase=m_TstTree.GetTstCase(bufCase, type);
		if(pcase)
		{
			pcases->InsertCase(pcase);
		}
	}

	if(pcases->empty())
	{
		delete pcases;
		return NULL;
	}

	return pcases;
}


HANDLE CSmpTester::ExeTest(CSmpTstNode* pcTstNode, DWORD dwPrio, ISmpIO* pIO)
{
	// CSmpTester::TstThreadWrap will delete pTstThrdPara
    TstThrdPara* pTstThrdPara=new TstThrdPara;
    pTstThrdPara->pthis=this;
    pTstThrdPara->pcTstNode=pcTstNode;
	pTstThrdPara->pIO=pIO;
    HANDLE hThrd=CreateThread(NULL, 0, &CSmpTester::TstThreadWrap, pTstThrdPara, CREATE_SUSPENDED, NULL);
    if(NULL==hThrd)
    {
    }
	else
	{
		if(INVALID_DWORD!=dwPrio)
		{
#ifdef WINCE
			if(!CeSetThreadPriority(hThrd, dwPrio))
#else
			if(!SetThreadPriority(hThrd, dwPrio))
#endif
			{
			}
		}
		ResumeThread(hThrd);
	}

    return hThrd;
}

DWORD CSmpTester::TstThreadWrap(LPVOID lpParameter)
{
    TstThrdPara* pTstThrdPara=(TstThrdPara*)lpParameter;
    pTstThrdPara->pthis->TstThread(pTstThrdPara->pcTstNode, pTstThrdPara->pIO);

	// delete TstThrdPara* pTstThrdPara, which is allocated by ExeTest
    delete pTstThrdPara;

    return 0;
}

VOID CSmpTester::TstThread(CSmpTstNode* pcTstNode, ISmpIO* pIO)
{
    LARGE_INTEGER liStart, liEnd, liDue;
    DWORD dwS, dwMS, dwNS;

    fnTestFun pfnTst=pcTstNode->GetTstFun();

	SmpTstFunCntx rslt;
	rslt.rslt=SMPTST_RSLT_UNKNWN;
	rslt.pstr=NULL;
	rslt.pIO=pIO;
    try
    {
        QueryPerformanceCounter(&liStart);
        (*pfnTst)(&rslt);
    }
    // some error occur on test function!
    catch (...)
    {
		if(pIO)
		{
			pIO->Printf(0, TEXT("exception in test case:%s!\r\n"), pcTstNode->GetTstName());
		}
    }

    QueryPerformanceCounter(&liEnd);
    liDue.QuadPart=liEnd.QuadPart-liStart.QuadPart;
    PerfermCntToSMN(&liDue, &m_liFreq, &dwS, &dwMS, &dwNS);
    pcTstNode->AddRslt(rslt.rslt, (SMPTST_RSLT_UNKNWN==rslt.rslt)?TEXT("Test result unkown!\r\n"):rslt.pstr, dwS, dwMS, dwNS);
    if(rslt.pstr)
    {
    	free(rslt.pstr);	// this buffer is malloc by SMPTST_XXX_RETURN -> ExpToBuf
    }
}


//
//==== smp test help functions ====
//


#define _UTEST_FLAG 0x54535455  //UTST
__declspec(allocate(".utest$__a")) int _utest_seg_a = _UTEST_FLAG;
__declspec(allocate(".utest$__d")) int _utest_seg_d = _UTEST_FLAG;
__declspec(allocate(".utest$__j")) int _utest_seg_j = _UTEST_FLAG;
__declspec(allocate(".utest$__z")) int _utest_seg_z = _UTEST_FLAG;


BOOL BuildUpDefTester(CSmpTester* ptester)
{
    SmpTstNode* pnodeBgn=NULL;
	SmpTstNode* pnodeEnd=NULL;

    FindEleInSeg(&_utest_seg_j, &_utest_seg_z, &CSmpTstNode::IsValidNode, &pnodeBgn, &pnodeEnd);
	if(FALSE==ptester->BuildUpTstTree(pnodeBgn, pnodeEnd))
	{
		return FALSE;
	}

	
    pnodeBgn=NULL;
	pnodeEnd=NULL;
    FindEleInSeg(&_utest_seg_d, &_utest_seg_j, &CSmpTstNode::IsValidNode, &pnodeBgn, &pnodeEnd);
	if(FALSE==ptester->BuildUpTstInitArray(pnodeBgn, pnodeEnd))
	{
		return FALSE;
	}

	pnodeBgn=NULL;
	pnodeEnd=NULL;
	FindEleInSeg(&_utest_seg_a, &_utest_seg_d, &CSmpTstNode::IsValidNode, &pnodeBgn, &pnodeEnd);
	if(FALSE==ptester->BuildUpTstCleanArray(pnodeBgn, pnodeEnd))
	{
		return FALSE;
	}

	return TRUE;

}



#endif  //#if (defined(SMPTST_IMP)|defined(KEN_LIB_IMP))

#endif  //#ifdef __cplusplus

#pragma warning( pop ) //#pragma warning(disable : 4297)

#endif  //#ifndef __SMP_TST_H__

